package com.runssnail.huafeiduo.api;

import com.alibaba.fastjson.JSON;
import com.runssnail.huafeiduo.api.common.RequestMethod;
import com.runssnail.huafeiduo.api.common.SignUtils;
import com.runssnail.huafeiduo.api.constants.Constants;
import com.runssnail.huafeiduo.api.exception.ApiException;
import com.runssnail.huafeiduo.api.internal.support.Validate;
import com.runssnail.huafeiduo.api.internal.utils.HttpUtils;
import com.runssnail.huafeiduo.api.request.Request;
import com.runssnail.huafeiduo.api.response.Response;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.util.Map;

/**
 * 默认的HuaFeiDuoClient服务实现
 *
 * @author zhengwei
 * @see HuaFeiDuoClient
 */
public class DefaultHuaFeiDuoClient implements HuaFeiDuoClient {

    protected final Log log = LogFactory.getLog(getClass());

    /**
     * 连接超时时间，单位毫秒，默认3秒
     */
    private int connectTimeout = Constants.DEFAULT_CONNECT_TIMEOUT;

    /**
     * 读取超时时间，单位毫秒，默认10秒
     */
    private int readTimeout = Constants.DEFAULT_READ_TIMEOUT;

    /**
     * app id
     */
    private String apiKey;

    /**
     * secretKey
     */
    private String secretKey;

    /**
     * @param apiKey    apiKey
     * @param secretKey secretKey
     */
    public DefaultHuaFeiDuoClient(String apiKey, String secretKey) {
        this.apiKey = apiKey;
        this.secretKey = secretKey;
    }

    @Override
    public <R extends Response> R execute(Request<R> req) throws ApiException {

        Validate.notNull(req, "request is required");

        return executeInternal(req.getApiUrl(), req);
    }

    /**
     * 执行请求
     *
     * @param apiUrl 实际的api url
     * @param req    请求
     * @param <R>    响应对象
     * @return 响应对象
     */
    private <R extends Response> R executeInternal(String apiUrl, Request<R> req) {

        if (log.isDebugEnabled()) {
            log.debug("execute start, apiUrl=" + apiUrl + ", request=" + req);
        }

        long start = System.currentTimeMillis();

        req.check();

        RequestMethod method = req.getMethod();

        String result = StringUtils.EMPTY;

        // 最终的请求数据
        Map<String, Object> params = req.getParams();

        params.put("api_key", this.apiKey);

        params.put("sign", SignUtils.buildSign(params, this.secretKey));

//        System.out.println(req.getApiUrl());
//        System.out.println(params);

        try {
            if (method.isGet()) {
                result = HttpUtils.doGet(apiUrl, params);
            } else {
                result = HttpUtils.doPost(apiUrl, buildPostParams(params), this.connectTimeout, this.readTimeout);
            }

            if (log.isDebugEnabled()) {
                log.debug("execute request success, apiUrl=" + apiUrl + ", request=" + req + ", result=" + result);
            }

        } catch (IOException e) {
            throw new ApiException("execute request error, apiUrl=" + apiUrl + ", request=" + req + ", result=" + result, e);
        }

        R res = buildResponse(result, req);

        res.setResponseBody(result);

        checkResponse(res);

        if (log.isDebugEnabled()) {
            log.debug("execute end, used total " + (System.currentTimeMillis() - start) + " ms, response=" + res);
        }
        return res;
    }

    /**
     * 检查响应数据是否正确
     *
     * @param res
     * @param <R>
     */
    protected <R extends Response> void checkResponse(R res) {

    }

    /**
     * 将响应数据生成对象
     *
     * @param result 响应字符串
     * @param req    请求对象
     * @param <R>    响应对象
     * @return 响应对象
     */
    protected <R extends Response> R buildResponse(String result, Request<R> req) {
        return JSON.parseObject(result, req.getResponseClass());
    }

    /**
     * 生成post数据，默认生成json数据
     *
     * @param params
     * @return
     */
    protected String buildPostParams(Map<String, Object> params) {
        return JSON.toJSONString(params);
    }

    public String getApiKey() {
        return this.apiKey;
    }

    public String getSecretKey() {
        return this.secretKey;
    }

    /**
     * http 连接超时时间，单位毫秒
     *
     * @return http 连接超时时间，单位毫秒
     */
    public int getConnectTimeout() {
        return connectTimeout;
    }

    /**
     * 设置 http 连接超时时间，单位毫秒
     *
     * @param connectTimeout http 连接超时时间，单位毫秒
     */
    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    /**
     * http 读取时间，单位毫秒
     *
     * @return http 读取时间，单位毫秒
     */
    public int getReadTimeout() {
        return readTimeout;
    }

    /**
     * 设置http 读取时间，单位毫秒
     *
     * @param readTimeout http 读取时间，单位毫秒
     */
    public void setReadTimeout(int readTimeout) {
        this.readTimeout = readTimeout;
    }

    @Override
    public void init() {

    }

    @Override
    public void close() {

    }
}
